<?php
class DBMSelect implements DBMQuery{
	private $entityMgr;
	private $command;
	
	public static function create($connectionID = "default"){
		// create the entity manager for the connection
		$entityMgr = DBMEntityManagerFactory::create($connectionID);
		
		// create the select
		$select = new DBMSelect($entityMgr);
		
		// return the select
		return $select;
	}
	
	public function toSQL(){
		return DBMConversor::commandToQuery($this->command, $this->entityMgr);
	}
	
	public function execute(){
		// execute the query
		return $this->entityMgr->findByCommand($this->command);
	}
	
	public function __construct(DBMEntityManager $entityMgr){
		// set the entity manager
		$this->entityMgr = $entityMgr;
		
		// create a new command
		$this->command = new DBMSelectCommand();
		
		// set the command operation
		$this->command->setOperation(DBMOperations::SELECT);
	}
	
	public function from($entityName, $alias = false){
		// search the entity
		$entity = DBMEntityHolder::getInstance()->getEntity($entityName);
		
		// check if the entity has been found
		if(is_null($entity)){
			throw new IllegalEntityException($entityName);
		}
		
		// check if the alias has been defined
		if($alias){
			$entity->setAlias($alias);
		}
	
		// set the entity in the command
		$this->command->addEntity($entity);
		
		// return
		return $this;
	}
	
	public function where($expression){
		// create the filter
		$filter = new DBMExpressionFilter($expression);
		
		// add in the command
		$this->command->addFilter($filter);
		
		// return
		return $this;
	}
	
	public function whereEq($field, $value){
		// create the filter
		$filter = new DBMLogicalFilter($field, DBMLogicalFilter::EQUALS, $value);
		
		// add in the command
		$this->command->addFilter($filter);
		
		// return
		return $this;
	}
	
	public function whereIn($field, $values){
		// create the filter
		$filter = new DBMInFilter($field, $values);
		
		// add in the command
		$this->command->addFilter($filter);
		
		// return
		return $this;
	}
	
	public function whereLike($field, $value){
		// create the filter
		$filter = new DBMLikeFilter($field, $value);
		
		// add in the command
		$this->command->addFilter($filter);
		
		// return
		return $this;
	}
	
	public function innerJoin($entityName, $alias, $filters){
		return $this->join(DBMJoin::INNER_JOIN, $entityName, $alias, $filters);
	}
	
	public function leftJoin($entityName, $alias, $filters){
		return $this->join(DBMJoin::LEFT_JOIN, $entityName, $alias, $filters);
	}
	
	public function rightJoin($entityName, $alias, $filters){
		return $this->join(DBMJoin::RIGHT_JOIN, $entityName, $alias, $filters);
	}
	
	public function outerJoin($entityName, $alias, $filters){
		return $this->join(DBMJoin::OUTER_JOIN, $entityName, $alias, $filters);
	}
	
	private function join($type, $entityName, $alias, $filters){
		// search the entity
		$entity = DBMEntityHolder::getInstance()->getEntity($entityName);
		
		// check if the entity has been found
		if(is_null($entity)){
			throw new IllegalEntityException($entityName);
		}
		
		// set the alias, if needed
		if($alias){
			$entity->setAlias($alias);
		}
		
		// format the filters
		if(is_string($filters)){
			$filters = array(
				new DBMExpressionFilter($filters)
			);
		} elseif(is_array($filters)){
			foreach($filters as $index => $filter){
				if(is_string($filter)){
					$filters[$index] = new DBMExpressionFilter($filter);
				}
			}
		}
		
		// create the join
		$join = new DBMJoin($entity, $type, $filters);
		
		// add the join in the command
		$this->command->addJoin($join);
		
		// return
		return $this;
	}
	
	public function distinct(){
		// set
		$this->command->setDistinct(true);
		
		// return
		return $this;
	}
	
	public function setResultLimit($limit){
		// set
		$this->command->setResultLimit($limit);
		
		// return
		return $this;
	}
	
	public function orderBy($field, $mode){
		// create the ordenator
		$ordenator = new DBMOrdenator($field, $mode);
		
		// add to the command
		$this->command->addOrdenator($ordenator);
		
		// return
		return $this;
	}
	
	public function enableLazyLoad(){
		// set
		$this->command->setLazyLoad(true);
		
		// return
		return $this;
	}
	
	public function disableLazyLoad(){
		// set
		$this->command->setLazyLoad(false);
		
		// return
		return $this;
	}
}
?>